/*
 * @Author: ipk518 121206530@qq.com
 * @Date: 2023-11-20 09:00:37
 * @LastEditors: ipk518 121206530@qq.com
 * @LastEditTime: 2024-03-08 15:50:36
 * @FilePath: /moduleTest/src/uart.c
 * @Description: 这是默认设置,请设置`customMade`, 打开koroFileHeader查看配置 进行设置: https://github.com/OBKoro1/koro1FileHeader/wiki/%E9%85%8D%E7%BD%AE
 */
// #include <asm-generic/termbits.h>
#include <sys/types.h>
#include <sys/select.h>
#include <pthread.h>
#include <fcntl.h>
#include <termios.h>
#include <unistd.h>
#include "uart.h"
#include "myLog.h"


static bool uartRunFlag = false;

int uartFd0=0;
int uartFd1=0;
int uartFd2=0;
int uartFd3=0;
int uartFd4=0;
  
static void setBaudrate(struct termios *opt, unsigned int baudrate)
{
    cfsetispeed(opt, baudrate);
    cfsetospeed(opt, baudrate);
}
 
static void setStopbit(struct termios *opt, const char *stopbit)
{
    if (0 == strcmp (stopbit, "1")) {
        opt->c_cflag &= ~CSTOPB;                                                           /* 1位停止位t          */
    }else if (0 == strcmp (stopbit, "1.5")) {
        opt->c_cflag &= ~CSTOPB;                                                           /* 1.5位停止位         */
    }else if (0 == strcmp (stopbit, "2")) {
        opt->c_cflag |= CSTOPB;                                                            /* 2 位停止位          */
    }else {
        opt->c_cflag &= ~CSTOPB;                                                           /* 1 位停止位          */
    }
}
 
static void setDataBit(struct termios *opt, unsigned int databit)
{
    opt->c_cflag &= ~CSIZE;
    switch (databit) {
    case 8:
        opt->c_cflag |= CS8;
    break;
    case 7:
        opt->c_cflag |= CS7;
    break;
    case 6:
        opt->c_cflag |= CS6;
    break;
    case 5:
        opt->c_cflag |= CS5;
    break;
    default:
        opt->c_cflag |= CS8;
    break;
    }
}
 
static void setParity(struct termios *opt, char parity)
{
    switch (parity) {
    case 'N':                                                                                   /* 无校验          */
    case 'n':
        opt->c_cflag &= ~PARENB;
        break;
    case 'E':                                                                                   /* 偶校验          */
    case 'e':
        opt->c_cflag |= PARENB;
        opt->c_cflag &= ~PARODD;
        break;
    case 'O':                                                                                   /* 奇校验           */
    case 'o':
        opt->c_cflag |= PARENB;
        opt->c_cflag |= ~PARODD;
        break;
    case 'S':
    case 's':
        opt->c_cflag &= ~PARENB;                                                                 /*清除校验位   disable pairty checking Space校验  */
        opt->c_cflag &= ~CSTOPB;        
        opt->c_iflag |= INPCK;   
        break;
    default:                                                                                    /* 其它选择为无校验 */
        opt->c_cflag &= ~PARENB;
        break;
    }
}


# define CRTSCTS  020000000000		/* flow control */
static int setPortAttr(int fd,int  baudrate, int  databit, const char *stopbit, char parity, int vtime,int vmin )
{
    struct termios opt;
    tcgetattr(fd, &opt);       //获取初始设置
        
    setBaudrate(&opt, baudrate);
    setDataBit(&opt, databit);
    setParity(&opt, parity);
    setStopbit(&opt, stopbit);
        
    opt.c_cflag &= ~CRTSCTS;   // 不使用硬件流控制
    opt.c_cflag |= CLOCAL | CREAD; //CLOCAL--忽略 modem 控制线,本地连线, 不具数据机控制功能, CREAD--使能接收标志 



 
    /*
    IXON--启用输出的 XON/XOFF 流控制
    IXOFF--启用输入的 XON/XOFF 流控制
    IXANY--允许任何字符来重新开始输出
    IGNCR--忽略输入中的回车
    */
    opt.c_iflag &= ~(IXON | IXOFF | IXANY);
    opt.c_oflag &= ~OPOST; //启用输出处理
	opt.c_iflag &= ~ICRNL; //禁止将输入的CR转换为NL
	
    /*
    ICANON--启用标准模式 (canonical mode)。允许使用特殊字符 EOF, EOL,
        EOL2, ERASE, KILL, LNEXT, REPRINT, STATUS, 和 WERASE，以及按行的缓冲。
    ECHO--回显输入字符
    ECHOE--如果同时设置了 ICANON，字符 ERASE 擦除前一个输入字符，WERASE 擦除前一个词
    ISIG--当接受到字符 INTR, QUIT, SUSP, 或 DSUSP 时，产生相应的信号
    */
    opt.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG); 
    opt.c_cc[VMIN] = vmin;   //设置非规范模式下的超时时长和最小字符数：阻塞模式起作用
    opt.c_cc[VTIME] = vtime; //VTIME与VMIN配合使用，是指限定的传输或等待的最长时间 单位：0.1S
        
    tcflush (fd, TCIFLUSH);                 /* TCIFLUSH-- update the options and do it NOW */
    return (tcsetattr (fd, TCSANOW, &opt)); /* TCSANOW--改变立即发生 */
}

/**
 * @description: 内部调用初始化串口和波特率
 * @param {char*} uart
 * @param {int } baudrate
 * @return {*}
 */
static int uartHandle(const char* uart,int  baudrate)
{
	const char *uart_out = "start uart application\r\n";
	int uartFd;
	uartFd = open(uart, O_RDWR | O_NOCTTY);//阻塞式读写       O_RDWR|O_NOCTTY      非阻塞| O_NDELAY | O_NONBLOCK
	if(uartFd < 0){
		qlog_i("open %s is failed",uart);
		return -1;
	}
    /* 115200 8n1      */
	if(setPortAttr(uartFd, baudrate, 8, "1", 'N',10,30 ) < 0){
		qlog_i("configure %s is failed",uart);
		return -1;
	}
	qlog_i("%s init sucessfully",uart);
	write(uartFd,uart_out, strlen(uart_out));

	return uartFd;
}

/**
 * @description: 串口数据发送
 * @param {char*} uart
 * @param {char} *data
 * @param {int} len
 * @return {*}
 */
int uartSendbuffer(const char* uart,char *data,int len)
{
	if(uartRunFlag != true){
		qlog_e("uart not working");
		return -1;
	}
	if(strcmp(uart,UART0) == 0){
		if(uartFd0 > 0){
			int res = write(uartFd0,data,len);
			if(res < 0){
				qlog_e("uart0 send is failed");
			}
			return res;
		}
	}

	if(strcmp(uart,UART1) == 0){
		if(uartFd1 > 0){
			int res = write(uartFd1,data,len);
			if(res < 0){
				qlog_e("uart1 send is failed");
			}
			return res;
		}
	}

	if(strcmp(uart,UART2) == 0){
		if(uartFd2 > 0){
			int res = write(uartFd2,data,len);
			if(res < 0){
				qlog_e("uart2 send is failed");
			}
			return res;
		}
	}

	if(strcmp(uart,UART3) == 0){
		if(uartFd3 > 0){
			int res = write(uartFd3,data,len);
			if(res < 0){
				qlog_e("uart3 send is failed");
			}
			return res;
		}
	}
    if(strcmp(uart,UART4) == 0) {
        if(uartFd4 > 0){
			int res = write(uartFd4,data,len);
			if(res < 0){
				qlog_e("uart4 send is failed");
			}
			return res;
		}
    }
	return -1;
}


/**
 * @description: 串口接收线程-（任意长度）
 * @param {void} *argc
 * @return {*}
 */
void *recv(void *argc)
{
    int ret = 0,recv_cnt = 0,uart_fd=0,rs_status=0,i=0;
	int res  = 0;
	static int nConnt = 0;
	fd_set rfds;
	uint8_t recbuf[1024];

	memset(recbuf,0,sizeof(recbuf));

    qlog_i("pthread_Recv = %lu",(unsigned long)pthread_self());//打印线程的tid号
    while(uartRunFlag)
    {
        FD_ZERO(&rfds);
		if(uartFd0 > 0){	//设置第一个需要监控的串口句柄
			FD_SET(uartFd0, &rfds);
			uart_fd = uartFd0;
		}
		if(uartFd1 > 0){	//设置第二个需要监控的串口句柄
			FD_SET(uartFd1, &rfds);
			if(uartFd1 > uart_fd)
			uart_fd = uartFd1;
		}
		if(uartFd2 > 0){	//设置第三个需要监控的串口句柄
			FD_SET(uartFd2, &rfds);
			if(uartFd2 > uart_fd)
			uart_fd = uartFd2;
		}
		if(uartFd3 > 0){	//设置第四个需要监控的串口句柄
			FD_SET(uartFd3, &rfds);
			if(uartFd3 > uart_fd)
			uart_fd = uartFd3;
		}
		ret = select(uart_fd + 1, &rfds, NULL, NULL, NULL);  //阻塞block mode
		if(ret > 0){
			if(FD_ISSET(uartFd0,&rfds)){	//判断是哪个串口句柄触发
				rs_status = 1;
			}
			if(FD_ISSET(uartFd1,&rfds)){	//判断是哪个串口句柄触发
				rs_status = 2;
			}
			if(FD_ISSET(uartFd2,&rfds)){	//判断是哪个串口句柄触发
				rs_status = 3;
			}
			if(FD_ISSET(uartFd3,&rfds)){	//判断是哪个串口句柄触发
				rs_status = 4;
			}
			if(rs_status == 1){				
				//触发成功后read串口数据，多数据则多次触发读取，知道触发结束。实现不定长接收
				recv_cnt = read(uartFd0,recbuf,1024);
                printf("uart0 recvice: %d, ",recv_cnt);
				for (i=0;i<recv_cnt;i++) {
					printf("buf[%d]=%#x, ",i,recbuf[i]);
				}
                fflush(stdout);
				printf("\r\n");
				write(uartFd0,recbuf,recv_cnt);
			}
			if(rs_status == 2){
				recv_cnt = read(uartFd1,recbuf,1024);
				printf("uart1 recvice: %d, ",recv_cnt);
				for (i=0;i<recv_cnt;i++) {
					printf("buf[%d]=%#x, ",i,recbuf[i]);
				}
                fflush(stdout);
				printf("\r\n");
				write(uartFd1,recbuf,recv_cnt);
			}
			if(rs_status == 3){
				recv_cnt = read(uartFd2,recbuf,1024);
                printf("uart2 recvice: %d, ",recv_cnt);
				for (i=0;i<recv_cnt;i++) {
					printf("buf[%d]=%#x, ",i,recbuf[i]);
				}
                fflush(stdout);
				printf("\r\n");
				write(uartFd2,recbuf,recv_cnt);
			}
			if(rs_status == 4){
				recv_cnt = read(uartFd3,recbuf,1024);
                printf("uart3 recvice: %d, ",recv_cnt);
				for (i=0;i<recv_cnt;i++) {
					printf("buf[%d]=%#x, ",i,recbuf[i]);
				}
                fflush(stdout);
				printf("\r\n");
				write(uartFd3,recbuf,recv_cnt);
			}
			rs_status = 0;
		}
    }
}

/**
 * @description: 串口初始化
 * @return {*}
 */
int uartInit()
{
    // uartFd0 = uartHandle(UART0,B115200);
    // uartFd1 = uartHandle(UART1,B115200);
    // uartFd2 = uartHandle(UART2,B115200);
    uartFd3 = uartHandle(UART3,B115200);
    // uartFd4 = uartHandle(UART4,B115200);
    uartRunFlag = true;
    pthread_t tid1;
    int ret = pthread_create(&tid1,NULL,recv,NULL);//创建线程
    return ret;
}